package com.grad.webstudy.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.grad.webstudy.annota.ApiAuthorization;
import com.grad.webstudy.constants.RedisConstants;
import com.grad.webstudy.constants.RoleConstants;
import com.grad.webstudy.context.UserContext;
import com.grad.webstudy.dao.ApplyDao;
import com.grad.webstudy.enums.ExceptionEnums;
import com.grad.webstudy.enums.ObjTypeEnums;
import com.grad.webstudy.enums.StatusEnums;
import com.grad.webstudy.exceptions.CustomException;
import com.grad.webstudy.model.Apply;
import com.grad.webstudy.model.Course;
import com.grad.webstudy.model.RoleUser;
import com.grad.webstudy.model.User;
import com.grad.webstudy.service.ApplyService;
import com.grad.webstudy.service.CourseService;
import com.grad.webstudy.service.RoleUserService;
import com.grad.webstudy.service.UserService;
import com.grad.webstudy.utils.RedisUtil;
import com.grad.webstudy.vo.ApplyVo;
import com.grad.webstudy.vo.CourseVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * @Description:
 * @Author: zjf
 * @Date: 2020/2/5 15:08.
 */

@Service
@Transactional
public class ApplyServiceImpl implements ApplyService {

    @Autowired
    private ApplyDao applyDao;

    @Autowired
    private UserService userService;


    @Autowired
    private CourseService courseService;

    @Autowired
    private RoleUserService roleUserService;

    @Autowired
    private RedisUtil redisUtil;


    @Override
    public boolean addApply(int objType, int objId, String applyDesc) {
        User loginUser = UserContext.getLoginUser();
        Apply apply = new Apply();
        apply.setObjId(objId);
        apply.setObjType(objType);
        apply.setStatus(StatusEnums.AUDITING.getStatus());
        apply.setTime(new Date());
        apply.setUserId(loginUser.getId());
        if (objType == ObjTypeEnums.COURSE.getObjType()) {
            if (Objects.isNull(applyDesc) || applyDesc.trim().length() <= 0) {
                apply.setApplyDesc("课程申请");
            }
        } else {
            if (Objects.isNull(applyDesc) || applyDesc.trim().length() <= 0) {
                apply.setApplyDesc("用户申请");
            }
        }
        redisUtil.delByPrefix(RedisConstants.REDIS_APPLY_KEY_PREFIX);

        return applyDao.insert(apply) > 0;
    }

    @Override
    public boolean undoApply(int id) {
        User loginUser = UserContext.getLoginUser();
        redisUtil.delByPrefix(RedisConstants.REDIS_APPLY_KEY_PREFIX);
        return applyDao.delete(id, loginUser.getId()) > 0;
    }

    @Override
    public boolean ChangeApply(int id, int status, String result) {

        if (applyDao.update(id, status, result) > 0) {
            redisUtil.delByPrefix(RedisConstants.REDIS_APPLY_KEY_PREFIX);
            Apply apply = applyDao.selectByPrimaryKey(id);

            int objId = apply.getObjId(); //获取审核对象id
            int objType = apply.getObjType();//获取审核对象类型

            //申请类型为用户时，对用户添加讲师角色
            if (objType == ObjTypeEnums.USER.getObjType()) {
                Integer userId = objId;
                List<Integer> roleIds = roleUserService.queryRoleIdsByUserId(userId);
                if (roleIds.contains(RoleConstants.TEACHER)) {
                    throw new CustomException(ExceptionEnums.CUSTOM_ERROR.getCode(), "已拥有讲师角色");
                }
                return roleUserService.addUserRole(new RoleUser(userId, RoleConstants.TEACHER));
            }


            //审核对象为课程时，更新课程状态
            if (objType == ObjTypeEnums.COURSE.getObjType()) {
                return courseService.changeCourseStatus(objId, status);
            }
        }
        return false;
    }

    @Override
    public PageInfo queryApplyByPageForAdmin(int currPage, int pageSize, Integer status) {
        validStatus(status);

        String key = RedisConstants.REDIS_APPLY_KEY_PREFIX + "queryAllAdmin" + currPage + "-" + pageSize + "-" + status;
        PageInfo<ApplyVo> result;

        if (redisUtil.hasKey(key)) {
            result = (PageInfo<ApplyVo>) redisUtil.get(key);
            return result;
        } else {
            Page page = PageHelper.startPage(currPage, pageSize);
            result = new PageInfo<>(transToApplyVo(applyDao.queryAll(null, status), true));

            result.setTotal(page.getTotal());
            result.setPageNum(currPage);
            result.setPageSize(pageSize);
            redisUtil.set(key, result);
            return result;
        }

    }

    @Override
    public PageInfo queryApplyByPageForEveryOne(int currPage, int pageSize, Integer status) {

        String key = RedisConstants.REDIS_APPLY_KEY_PREFIX + "queryAllEveryOne" + currPage + "-" + pageSize + "-" + status;

        User loginUser = UserContext.getLoginUser();
        validStatus(status);
        PageInfo<ApplyVo> result;
        if (redisUtil.hasKey(key)) {
            result = (PageInfo<ApplyVo>) redisUtil.get(key);
            return result;
        } else {
            Page page = PageHelper.startPage(currPage, pageSize);

            result = new PageInfo<>(transToApplyVo(applyDao.queryAll(loginUser.getId(), status), false));

            result.setTotal(page.getTotal());
            result.setPageNum(currPage);
            result.setPageSize(pageSize);
            redisUtil.set(key, result);
            return result;
        }
    }


    public boolean updateStatus(Integer objId, Integer objType, Integer status) {

        redisUtil.delByPrefix(RedisConstants.REDIS_APPLY_KEY_PREFIX);

        return applyDao.updateStatus(objId, objType, status) > 0;
    }

    @Override
    public boolean updateStatusForDelete(List<String> objIds, Integer objType) {
        redisUtil.delByPrefix(RedisConstants.REDIS_APPLY_KEY_PREFIX);

        return applyDao.updateStatusForDelete(objIds, objType) == objIds.size();
    }


    private List<ApplyVo> transToApplyVo(List<Apply> applies, boolean forAdmin) {
        User loginUser = UserContext.getLoginUser();
        List<ApplyVo> result = new ArrayList<>(applies.size());

        if (!forAdmin) {
            String username = loginUser.getUsername();
            for (Apply apply : applies) {
                result.add(new ApplyVo.Builder()
                        .setId(apply.getId())
                        .setUserName(username)
                        .setResult(apply.getResult())
                        .setStatus(apply.getStatus())
                        .setStatusMsg(StatusEnums.getDescByStatus(apply.getStatus()))
                        .setApplyDesc(apply.getApplyDesc())
                        .setObjId(apply.getObjId())
                        .setObjType(ObjTypeEnums.getDesc(apply.getObjType()))
                        .setObjTypeCode(apply.getObjType())
                        .setTime(apply.getTime())
                        .setDealTime(apply.getDealTime())
                        .build()
                );
            }
        } else {
            boolean isSameUser = false;//判断list中的是否是同一个User
            String username = "";
            for (int i = 0; i < applies.size(); i++) {
                String courseName = "";
                Apply apply = applies.get(i);
                if (!isSameUser) {
                    username = userService.selectUserForSystem(apply.getUserId()).getUsername();
                    username = username.equals("admin") ? "官方" : username;
                }
                if (i < applies.size() - 1) {
                    if (apply.getUserId() == applies.get(i + 1).getUserId()) {
                        isSameUser = true;
                    } else {
                        isSameUser = false;
                    }
                }
                if (apply.getObjType() == ObjTypeEnums.COURSE.getObjType()
                    && apply.getStatus() != StatusEnums.DELETE.getStatus()) {
                    CourseVo course = courseService.queryById(apply.getObjId(), null);
                    courseName = "  ,课程名称：" + course.getClassName();
                }
                result.add(new ApplyVo.Builder()
                        .setId(apply.getId())
                        .setUserName(username)
                        .setResult(apply.getResult())
                        .setStatus(apply.getStatus())
                        .setStatusMsg(StatusEnums.getDescByStatus(apply.getStatus()))
                        .setApplyDesc(apply.getApplyDesc() + (courseName.length() > 0 ? (courseName) : ""))
                        .setObjId(apply.getObjId())
                        .setObjType(ObjTypeEnums.getDesc(apply.getObjType()))
                        .setObjTypeCode(apply.getObjType())
                        .setDealTime(apply.getDealTime())
                        .setTime(apply.getTime())
                        .build()
                );
            }

        }

        return result;
    }

    private void validStatus(Integer status) {
        if (status != null) {
            if (status < 1 || status > 5) {
                throw new CustomException(ExceptionEnums.CUSTOM_ERROR.getCode(),
                        "参数status[" + status + "]错误");
            }
        }
    }
}
